#include "IOFileDisk.h"
#include "include/PowerLibraryEngine.h"
#include "FileSystem.h"

#include "Config.h"

#ifdef __COMPILE_WIN32__
    #include <io.h>
    #define COPY_FINDDATA_W32(f,c)	f.Name = c.name;		\
        f.Attrib = c.attrib;								\
        f.TimeCreate = (u32)c.time_create;					\
        f.TimeAccess = (u32)c.time_access;					\
        f.TimeWrite = (u32)c.time_write;					\
        f.Size = (u32)c.size;
#else
    #ifdef __COMPILE_LINUX__
        #include <stdio.h>
        #include <dirent.h>
        #include <sys/types.h>
        #include <unistd.h>
        #include <sys/stat.h>
        #include <string.h>
        #define _A_SUBDIR   1
        #define COPY_FINDDATA_LINUX(f,c) stringc Name(c->d_name);   \
            f.Name = Name;                                          \
            struct stat stat_buf;                                   \
            stat(c->d_name, &stat_buf);                             \
            int is_dir = S_ISDIR(stat_buf.st_mode);                 \
            f.Attrib = is_dir?_A_SUBDIR:0;                          \
            f.Size = (u32)stat_buf.st_size;

    #endif
#endif

CIOFileDisk::CIOFileDisk(stringc dir,stringc filename,CFileSystem *fsp):CIOFile(dir,filename,fsp),FileBuffer(NULL)
{
}

CIOFileDisk::~CIOFileDisk()
{
}

u32 CIOFileDisk::CopyFromFileToMemory(u32 Size)
{
	if (!fd.IsDirectory && !fd.IsLoaded)
	{
		if (!FileBuffer)
		{
			FileBuffer = fopen(fd.CompleteName.c_str(),"rb");
		}

		if (FileBuffer)
		{
			pLogDebug << "CIOFileDisk::CopyFromFileToMemory: File " << fd.CompleteName << endl;
			if (!Buffer)
				Buffer = new u8[fd.Size];

			u32 Result = fread(Buffer,1,Size,FileBuffer);

			if (Result == Size)
			{
				pLogDebug << "Finished reading file OK\n";
			}
			else
			{
				pLogDebug << "File modified. Using it. Setting new value to" << Result << endl;
				Size = Result;
			}

			fclose(FileBuffer);
			fd.IsLoaded = true;
			FileBuffer = NULL;
			return Result;
		}
		else
		{
			pLogDebug << "CIOFileDisk:: File " << fd.CompleteName << " not found" << endl;
			return 0;
		}
	}

	if (fd.IsLoaded)
		return fd.Size;

	return 0;
}

bool CIOFileDisk::OpenFileForWriting(stringc Name)
{
	if (IsDirectoryString(fd.CompleteName))
	{

	}
	else
	{
		FileBuffer = fopen(fd.CompleteName.c_str(),"wb");
	}

	if (FileBuffer)
	{
		fd.Size = 0;
		fd.FileNameOnly = Name;
		fd.IsDirectory = IsDirectoryString(fd.CompleteName);
		fd.IsLoaded = false;
		return true;
	}
	else
	{
		return false;
	}

	return false;
}

IIOFile *CIOFileDisk::CreateBinaryFile(stringc Name)
{
	CIOFile *FileCreated = fs->GetNewCIOFile(fd.CompleteName,Name);
	FileCreated->fd.CompleteName = fd.CompleteName + Name;
	if (!FileCreated->OpenFileForWriting(Name))
	{
		DEALLOCATE(FileCreated);
		return NULL;
	}

	return FileCreated;
}

u32 CIOFileDisk::WriteBinary(void *Buffer,u32 Size)
{
	if (FileBuffer)
		return fwrite(Buffer,Size,1,FileBuffer);
	return 0;
}

bool CIOFileDisk::CloseFile()
{
	//	bool Ret = CloseFile(FileBuffer);
	bool Ret = (fclose(FileBuffer)!=0);
	FileBuffer = NULL;
	return Ret;
}

bool CIOFileDisk::FindFirst(stringc Path,FindDataStrc *fdata)
{
#ifdef __COMPILE_LINUX__
    Dir = opendir(Path.c_str());
    if (Dir)
    {
        struct dirent *dp;
        dp = readdir(Dir);
//        COPY_FINDDATA_LINUX((*fdata),dp);
//        #define COPY_FINDDATA_LINUX(f,c)
        stringc Name(dp->d_name);
        fdata->Name = Name;
        struct stat stat_buf;
        stringc cn = fd.CompleteName;
        if (cn[cn.size()-1] != DIR_SEPARATOR_CHAR)
            cn += DIR_SEPARATOR_STR;

        cn += dp->d_name;
        int rs = stat(cn.c_str(), &stat_buf);
        int is_dir = S_ISDIR(stat_buf.st_mode);
        fdata->Attrib = is_dir?_A_SUBDIR:0;
        fdata->Size = (u32)stat_buf.st_size;

        return 1;
    }
    return 0;
#else
	struct _finddata_t temp;
	SearchingID = _findfirst(Path.c_str(),&temp);
	COPY_FINDDATA_W32((*fdata),temp);
	return SearchingID!=-1;
#endif
}

bool CIOFileDisk::FindNext(FindDataStrc *fdata)
{
#ifdef __COMPILE_LINUX__
    struct dirent *dp = readdir(Dir);
    if (dp != NULL)
    {
//        COPY_FINDDATA_LINUX((*fdata),dp);
        stringc Name(dp->d_name);
        fdata->Name = Name;
        struct stat stat_buf;
        stringc cn = fd.CompleteName;
        if (cn[cn.size()-1] != DIR_SEPARATOR_CHAR)
            cn += DIR_SEPARATOR_STR;

        cn += dp->d_name;
        int rs = stat(cn.c_str(), &stat_buf);
        int is_dir = S_ISDIR(stat_buf.st_mode);
        fdata->Attrib = is_dir?_A_SUBDIR:0;
        fdata->Size = (u32)stat_buf.st_size;
        return false;
    }
    return true;
#else
	struct _finddata_t temp;
	s32 ret = _findnext(SearchingID,&temp);
	COPY_FINDDATA_W32((*fdata),temp);
	return ret==-1;
#endif
}

bool CIOFileDisk::FindClose()
{
#ifdef __COMPILE_LINUX__
    closedir(Dir);
#else
	int Ret = _findclose(SearchingID);
	SearchingID=-1;
	return Ret!=-1;
#endif
}

bool CIOFileDisk::IsSubDir(FindDataStrc *fdata)
{
	if (fdata->Attrib&_A_SUBDIR)
		return true;
	else
		return false;
}
